﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace KinectServer
{
    public class Server
    {
        // the EP corresponding to this server
        public static IPEndPoint serverEP = new IPEndPoint(IPAddress.Loopback, 8111);
        // the EP corresponding to the client
        public static IPEndPoint clientEP = new IPEndPoint(IPAddress.Loopback, 8112);
        private static System.Diagnostics.Stopwatch stopwatch;
        private static TcpListener server;
        private static TcpClient client;
        static readonly object locker = new object();
        public static bool logging = false;
        public static int INT64_BYTES = BitConverter.GetBytes(Int64.MaxValue).Length;
        public static int DOUBLE_BYTES = BitConverter.GetBytes(Double.MaxValue).Length;

        public static void StartServer()
        {
            stopwatch = Program.stopwatch;
            stopwatch.Start();
            Connect();
            if (logging) Console.WriteLine("Listening for remoteEP");
            Thread t = new Thread(() => Server.KinectServer());
            t.Start();
        }

        private static void Connect()
        {
            if (server == null)
            {
                server = new TcpListener(IPAddress.Any, Server.serverEP.Port);
                server.Server.SendTimeout = 999999;
                server.Start();
            }
            
            client = server.AcceptTcpClient();
        }

        private static void KinectServer()
        {
            while (Program.running)
            {
                TimeSpan startTime = Program.stopwatch.Elapsed;
                if(logging)Console.WriteLine("Waiting for a connection");
                Send(Program.skeletonFrame);
                TimeSpan endTime = stopwatch.Elapsed;
                TimeSpan timeDiff = endTime - startTime;
                int msDiff = (int)(timeDiff.Milliseconds);
                Sleep(msDiff);
            }
        }

        private static void Send(KinectSkeletonFrame skeletonFrame)
        {
            if (!client.Connected)
            {
                //server.Stop();
                Connect();
               // return;
            }

            byte[] buffer;
            if (skeletonFrame != null)
            {
                try
                {
                    lock (locker)
                    {
                        buffer = skeletonFrame.ToBytes();
                    }
                    using (NetworkStream stream = client.GetStream())
                    {
                        stream.Write(buffer, 0, buffer.Length);
                        if (logging) Console.WriteLine("Sent: {0}", buffer);
                    }
                }
                catch (Exception e) { Console.WriteLine("Failed to Send\n{0}", e.Message); }
            }
            else
            {
                Console.WriteLine("SkeletonFrame not ready");
            }
        }

        private static void Sleep(int msDiff)
        {
            if (msDiff >= 0 && msDiff < Program.mspf)
            {
                if (logging) Console.WriteLine("Sleeping for {0} ms", Program.mspf - msDiff);
                Thread.Sleep(Program.mspf - msDiff);
            }
            else
            {
                Console.WriteLine("Not sleeping, as send process took {0} ms", msDiff);
            }
        }

    }
}
